package com.t.blog.filter;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.Digester;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import cn.hutool.jwt.JWTValidator;
import com.t.blog.service.SysUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import com.t.blog.dto.SysUserDto;
import org.t.pro.vo.SysUser;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;

/**
 * 〈一句话功能简述〉<br>
 * 〈JWT过滤器〉
 *
 * @author a0000
 * @create 2023/11/16 00:03
 * @since 1.0.0
 */
public class JWTFilter extends OncePerRequestFilter {

    @Autowired
    private SysUserService service;

    private final Long TIME_DIFF = 60*2L;

    private final ArrayList<String> REQUEST_LIST = new ArrayList<>();

    @Autowired
    private  UserDetails userDetails;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        if (!checkToken(request)) {
        //请求校验不通过，要求用户重新登陆
            SecurityContextHolder.clearContext();
        }else{
            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userDetails.getUsername(), null);
            SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
        }
        filterChain.doFilter(request,response);
    }

    private boolean checkToken(HttpServletRequest request) {
//        从请求中获取token
        if (request.getHeader("Auth").isEmpty()) {
            return false;
        }

        String auth = request.getHeader("Auth");
        String token = auth.split(" ")[1];
        //        检查Request的合法性
        if (token.isEmpty() || !checkRequest(request,token)){
            return false;
        }
        final JWT jwt = JWTUtil.parseToken(token);
        String username = (String)jwt.getPayload("username");
        SysUserDto currentUser = service.getUserByUsername(username);
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(currentUser,sysUser);
        String tokenSalt = currentUser.getTokenSalt();
        if (!JWTUtil.verify(token, tokenSalt.getBytes())) {
            return false;
        }
        try {
            JWTValidator.of(token).validateDate(DateUtil.date());
        }catch (Exception e){
            currentUser.setTokenSalt(RandomUtil.randomString(6));
            service.saveOrUpdate(sysUser);
            return false;
        }
        return true;
    }

//    检查Request是否合法 1.请求时间是否合法 2.请求随机数是否一致
    private boolean checkRequest(HttpServletRequest request,String token) {
        String timeStamp = request.getHeader("timeStamp");
        String nonce = request.getHeader("nonce");

        long currentTime = System.currentTimeMillis()/1000;
        //非法请求
        if (currentTime -  Long.valueOf(timeStamp) > TIME_DIFF) {
            return false;
        }
        Digester md5 = new Digester(DigestAlgorithm.MD5);
        String requestNonce = md5.digestHex(token+nonce);
        if (REQUEST_LIST.contains(requestNonce)){
            return false;
        }
//        如果集合中不存在，则说明该请求的随机数是没有出现过的，就可以继续下一步的请求校验了
        REQUEST_LIST.add(requestNonce);
        return true;
    }


}
